package ca.cbc.panacea.elixir.service;

import ca.cbc.panacea.elixir.entity.PanaceaInstance;
import ca.cbc.panacea.elixir.exception.ElixirException;
import ca.cbc.panacea.elixir.persistence.EntityFacade;
import ca.cbc.panacea.elixir.persistence.Transactional;
import ca.cbc.panacea.elixir.util.PanaceaDaemon;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import java.io.Serializable;
import java.util.List;


/**
 * @author : Arash Bizhanzadeh <arash.bizhanzadeh@cbc.ca>
 *         Date: 11-11-17
 *         Time: 10:58 AM
 */
@ApplicationScoped()
public class PanaceaService {



    private EntityFacade entityFacade = EntityFacade.instance;
    private List<PanaceaInstance> instances;
    private Logger logger = LoggerFactory.getLogger(PanaceaService.class);

    @PostConstruct
    public  void create() throws ElixirException {
        logger.debug("Creating Panacea Service");
        if(entityFacade == null){
            logger.error("EntityFecade is null");
        }
        entityFacade.beginTransaction();
        instances =  entityFacade.get().createQuery(" SELECT p from PanaceaInstance p ").getResultList();
        logger.debug("Instances had {} elements" , instances.size());

        for(PanaceaInstance instance : instances){
            if(!Strings.isNullOrEmpty(instance.getProcessId())){
                logger.info("Instance {} was running before shutdown. Start it", instance.getDirectory());
                String oldId = PanaceaDaemon.probe(instance);
                    if(Strings.isNullOrEmpty(oldId)){
                        PanaceaDaemon.start(instance);
                        instance.setProcessId(PanaceaDaemon.probe(instance));
                        logger.info("Instace {} started successfully.");
                    }
                    else{
                        logger.warn("Instance {} was already running, might be a bug in elixir.", instance.getDirectory());
                        instance.setProcessId(oldId);
                    }
                }
        }
        entityFacade.commitTransaction();
    }

    @PreDestroy
    public void destroy(){
        logger.info("Shutting down all the instances");
        for (PanaceaInstance instance : getInstances()) {
            try {
                if (instance.isRunning()) {
                    PanaceaDaemon.stop(instance);
                }
            } catch (ElixirException e) {
                logger.error("ERROR: could not stop process for {}", instance.getDaemonPidFile());
            }
        }
    }

    public void createModule(String name, String directory){
        createSvnDirectory(directory);
        saveToDatabase(name, directory);


    }



    public void saveProperties(String moduleName){

    }

    private void saveToDatabase(String name, String directory) {

    }

    private void createSvnDirectory(String directory) {

    }


    @SuppressWarnings("unchecked")
    public List<PanaceaInstance> getInstances() {
        return instances;
    }


    public void save(PanaceaInstance instance) throws ElixirException {
        try{
            entityFacade.beginTransaction();
            entityFacade.get().persist(instance);
            entityFacade.commitTransaction();
            if (! instances.contains(instance)){
                instances.add(instance);
            }
        }catch (Exception e){
            throw new ElixirException("Could not write to the database");
        }
    }

    public void setProcessId(PanaceaInstance instance, String processId) throws ElixirException {
        try{
            logger.debug("Setting process id for {} to {}", instance.getDirectory(), instance.getProcessId());
            entityFacade.beginTransaction();
            instance.setProcessId(processId);
            entityFacade.get().merge(instance);
            entityFacade.commitTransaction();
            logger.debug("Transaction committed successfully");
        }catch (Exception e){
            logger.error("Could not update record ", e);
            throw new ElixirException("Could not update record");
        }
    }

    public void delete(PanaceaInstance instance) throws ElixirException {
        try {
            entityFacade.beginTransaction();
            Object o = entityFacade.get().find(PanaceaInstance.class, instance.getDirectory());
            entityFacade.get().remove(o);
            entityFacade.commitTransaction();
            instances.remove(instance);
        } catch (Exception e) {
            logger.error("error deleting instance " + instance.getDirectory(), e);
            entityFacade.rollbackTransaction();
            throw new ElixirException("Could not delete instance " + instance.getDirectory());
        }
    }

    public FacesMessage start(PanaceaInstance instance) {

        try {
            String processId = PanaceaDaemon.start(instance);
            try{
                entityFacade.beginTransaction();
                instance.setProcessId(processId);
                entityFacade.get().merge(instance);
                entityFacade.commitTransaction();
            }catch (Exception e){
                logger.error("Error updating instance " + instance.getDirectory(), e);
                return new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error updating database ", e.getMessage());
            }
        } catch (ElixirException e) {
            return new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error starting process", e.getMessage());
        }
        return new FacesMessage(FacesMessage.SEVERITY_INFO, "Successful", "Process started successfully " + instance.isRunning());
    }

    public FacesMessage stop(PanaceaInstance instance) {
         FacesMessage msg = null;
        try{
            if (PanaceaDaemon.stop(instance)){
                msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Success", "Process stopped successfully.");
                entityFacade.beginTransaction();
                instance.setProcessId("");
                entityFacade.get().merge(instance);
                entityFacade.commitTransaction();
            }

        } catch (ElixirException e) {
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Error", e.getMessage());
        }
        return msg;
    }
}
